#include <iostream>
#include <string>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h> 
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include "protocol.hpp"

using namespace std;

void *Routiue(void* arg)
{
  int sock = *(int*)arg;
  delete (int*)arg;

  while(true){
    request_t rq;
    response_t rsp = {0, 0};
    ssize_t s = recv(sock, &rq, sizeof(rq), 0);
    if(s > 0){
      switch(rq.op){
        case '+':
          rsp.result = rq.x + rq.y;
          break;
        case '-':
          rsp.result = rq.x - rq.y;
          break;
        case '*':
          rsp.result = rq.x * rq.y;
          break;
        case '/':
          if(rq.y == 0){
            rsp.code = 1; //除零
          }
          else 
            rsp.result = rq.x / rq.y;
          break;
        case '%':
          if(rq.y == 0){
            rsp.code = 2; //除零
          }
          else 
            rsp.result = rq.x % rq.y;
          break;
        default:
          rsp.code = 3; //非法运算
          break;
      }
      send(sock, &rsp, sizeof(rsp), 0);
    }// if end 
    else if(s == 0){
      cout << "client quit" << endl;
      break;
    }
    else{
      break;
    }
  }//while end 

  return nullptr;
}

// ./server port
int main(int argc, char* argv[])
{
  if(argc != 2){
    cout << "Usage: " << argv[0] << " port" << endl;
    exit(1);
  }

  int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  if(listen_sock < 0){
    exit(2);
  }

  struct sockaddr_in local;
  memset(&local, 0, sizeof(local));
  local.sin_family = AF_INET;
  local.sin_port = htons(atoi(argv[1]));
  local.sin_addr.s_addr = htonl(INADDR_ANY);

  if(bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){
    exit(3);
  }

  if(listen(listen_sock, 5) < 0){
    exit(4);
  }

  struct sockaddr_in peer;
  for(;;){
    socklen_t len = sizeof(peer);
    int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);
    if(sock < 0){
      continue;
    }
    pthread_t tid;
    int *p = new int(sock);
    pthread_create(&tid, nullptr, Routiue, p);
  }
}
